跳到主要内容

Golang 序列化

二进制序列化

使用 gobbase64

这里的 gob 是一个官方的二进制序列库

import (
"bytes"
"encoding/base64"
"encoding/gob"
"fmt"
)

type SX map[string]interface{}

// go binary encoder
func ToGOB64(m SX) string {
b := bytes.Buffer{}
e := gob.NewEncoder(&b)
err := e.Encode(m)
if err != nil {
fmt.Println(`failed gob Encode`, err)
}
return base64.StdEncoding.EncodeToString(b.Bytes())
}

// go binary decoder
func FromGOB64(str string) SX {
m := SX{}
by, err := base64.StdEncoding.DecodeString(str)
if err != nil {
fmt.Println(`failed base64 Decode`, err)
}
b := bytes.Buffer{}
b.Write(by)
d := gob.NewDecoder(&b)
err = d.Decode(&m)
if err != nil {
fmt.Println(`failed gob Decode`, err)
}
return m
}

func main() {
data := SX{}
data["01"] = "Hello"
data["02"] = 1999
data["03"] = 127.021
data["04"] = "World"

str := ToGOB64(data)
fmt.Println(str)

deData := FromGOB64(str)
for k, v := range deData {
fmt.Printf("key: %s, value: %v \n", k, v)
}
}

output:

Ev+BBAEBAlNYAf+CAAEMARAAAE7/ggAEAjAyA2ludAQEAP4PngIwMwdmbG9hdDY0CAoA+NNNYhBYwV9AAjA0BnN0cmluZwwHAAVXb3JsZAIwMQZzdHJpbmcMBwAFSGVsbG8=
key: 02, value: 1999
key: 03, value: 127.021
key: 04, value: World
key: 01, value: Hello

JSON 序列化与反序列化

Golang 中,要用到 JSON 有关方法需要 import "encoding/json"

struct 的序列化

import (
"encoding/json"
"fmt"
)

type Human struct {
Name string `json:"name"`
Age int `json:"age"`
Gender int `json:"gender"`
}

func main() {
human := Human{
Name: "张三丰",
Age: 18,
Gender: 0,
}

data, err := json.Marshal(&human)
if err != nil{
fmt.Printf("error: %v", err)
}

fmt.Printf("序列化结果: %v", string(data))
}

输出:

{"name":"张三丰","age":18,"gender":0}

注意,这里的属性名称都是大写的,由于这个方法是 json 这个包的,如果我们结构体字段小写,json 包的方法是无法使用本包结构体的首字母小写的字段。因为是私有的,不能跨包使用。

反序列化

func main() {
str := "{\"name\":\"张三丰\",\"age\":18,\"gender\":0}"
var human Human
err := json.Unmarshal([]byte(str), &human) // 注意参数二要传递指针
if err != nil{
fmt.Printf("error: %v", err)
}

fmt.Printf("序列化结果: %v", human)
}

map 的序列化

func main() {
human := make(map[string]interface{})
human["Name"] = "张三丰"
human["Age"] = 18
human["Gender"] = 0

data, err := json.Marshal(human)
if err != nil{
fmt.Printf("error: %v", err)
}

fmt.Printf("序列化结果: %v", string(data))
}

反序列化

func main() {
str := "{\"name\":\"张三丰\",\"age\":18,\"gender\":0}"
var m map[string]interface{} // 反序列化不需要 make,因为 Unmarshal 封装了 make 操作
err := json.Unmarshal([]byte(str), &m) // 依旧是传递引用
if err != nil{
fmt.Printf("error: %v", err)
}

fmt.Printf("序列化结果: %v", m)
}

slice 的序列化

func main() {
human := make(map[string]interface{})
human["Name"] = "张三丰"
human["Age"] = 18
human["Gender"] = 0
// 创建一个 slice
var arr []map[string]interface{}
arr = append(arr, human, human)

data, err := json.Marshal(arr)
if err != nil {
fmt.Printf("error: %v", err)
}

fmt.Printf("序列化结果: %v", string(data))
}

结果

[   
{"Age":18,"Gender":0,"Name":"张三丰"},
{"Age":18,"Gender":0,"Name":"张三丰"}
]

反序列化和上面是一样的,都是传递引用

JSON 反序列化文件

json 数据解码的两种方法 NewDecoder 与 Unmarshal

golang 中处理 http 响应数据解码,一般有两种方式

使用 Unmarshal 的方式:

func HandleUse(w http.ResponseWriter, r *http.Request) {
var u Use
data, err := ioutil.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
if err := json.Unmarshal(data, &u); err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "姓名:%s,年龄:%d", u.Name, u.Age)

}

使用 json.NewDecoder 解码

func HandleUse(w http.ResponseWriter, r *http.Request) {
var u Use
if err := json.NewDecoder(r.Body).Decode(&u); err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "姓名:%s,年龄:%d", u.Name, u.Age)

}

区别:

1、json.NewDecoder 是从一个流里面直接进行解码,代码精干 2、json.Unmarshal 是从已存在与内存中的 json 进行解码 3、相对于解码 json.NewEncoder 进行大 JSON 的编码比 json.marshal 性能高,因为内部使用 pool

场景应用:

1、json.NewDecoder 用于 http 连接与 socket 连接的读取与写入,或者文件读取 2、json.Unmarshal 用于直接是 byte 的输入

Reference

Golang serialize and deserialize back